#include "index_merger.h"

using namespace ::google::protobuf; 

int IndexMerger::MergeIndex(MergeList* mergeList, SearchTermList* termList)
{
    GOOGLE_PROTOBUF_VERIFY_VERSION;
    uint64_t sign = 0; 
    int level = 0;
    bool search_flag = false;
    int idx[SEARCH_TERM_NUM][MAX_HOMOLOGY_NUM] = {0};
    int list_idx[SEARCH_TERM_NUM][MAX_HOMOLOGY_NUM+1] = {0};
    int termUnitNum = termList->termunit_size();
    for(int i = 0; i < termUnitNum; ++i)
    {
        search_flag = false;
        TermUnit* termUnit = termList->mutable_termunit(i);
        int termNum = termUnit->term_size();
        for(int j = 0; j < termNum; ++j)
        {
            Term* term = termUnit->mutable_term(j);
            sign = term->sign();
            level = term->level();
            if(m_indexReader->ReadIndex(sign, &m_indexList[i][j], level) != S_RET)
            {
                WARNING("term[%s] is not found", term->termstr().c_str());
            }
            else
                search_flag = true;
        }
        if(!search_flag)
        {
            WARNING("term_info_id[%d], index is not foud!", i);
            return E_RET;
        }
    }

    while(true)
    {
        int32_t maxId = -1;
        int max_idx = 0;
        int max_idx_idx = 0;
        int termUnitNum = termList->termunit_size();
        for(int i = 0; i < termUnitNum; ++i)
        {
            int32_t min = INT_MAX;
            int min_idx = 0;
            int termNum = termList->mutable_termunit(i)->term_size();
            for(int j = 0; j < termNum; ++j)
            {
                if(m_indexList[i][j].idxHead == NULL || idx[i][j] >= (int)m_indexList[i][j].idxHead->num_idx)
                    continue;
                uint32_t id = m_indexList[i][j].idxIndex[idx[i][j]].id;
                if(min > (int32_t)id)
                {
                    min = id;
                    min_idx = j;
                }
            }
            if(min == INT_MAX)
                goto END;
            if(min > maxId)
            {
                maxId = min;
                max_idx = i;
                max_idx_idx = min_idx;
            }
        }
        bool hasMerge = true;
        for(int i = 0; i < termUnitNum; ++i)
        {
            bool needMerge = false;
            int termNum = termList->mutable_termunit(i)->term_size();
            for(int j = 0; j < termNum; ++j)
            {
                if(NULL == m_indexList[i][j].idxHead)
                    continue;
                if(i == max_idx && j == max_idx_idx)
                {
                    list_idx[i][++list_idx[i][0]] = j;
                    ++idx[i][j];
                    needMerge = true;
                    continue;
                }
                int low = idx[i][j];
                int high = m_indexList[i][j].idxHead->num_idx-1;
                int mid = 0;
                idx_index_t* idx_index = m_indexList[i][j].idxIndex;
                while(low < high - 1)
                {
                    mid = (low+high)/2;
                    if(idx_index[mid].id >= maxId)
                        high = mid;
                    else
                        low = mid;
                }
                if(idx_index[low].id >= maxId)
                    idx[i][j] = low;
                else if(idx_index[mid].id >= maxId)
                    idx[i][j] = mid;
                else
                    idx[i][j] = high;
                if(idx_index[idx[i][j]].id == maxId)
                {
                    list_idx[i][++list_idx[i][0]] = j;
                    needMerge = true;
                    ++idx[i][j];
                }
            }
            if(!needMerge)
                hasMerge = false;
        }
        if(hasMerge)
        {
            UnitInfo* unit = mergeList->add_unit();
            unit->set_id(maxId);
            unit->set_pos(-1);
            int32_t weight = 0;
            int listIdx = 0;
            for(int i = 0; i < termUnitNum; ++i)
            {
                for(int j = 1; j <= list_idx[i][0]; ++j)
                {
                    listIdx = list_idx[i][j];
                    weight += m_indexList[i][listIdx].idxIndex[idx[i][listIdx]-1].weight;
                }
            }
            unit->set_weight(weight);
        }
    }
END:
    if(mergeList->unit_size() > 0)
        return S_RET;
    else
        return E_RET;
}





















/* vim: set expandtab ts=4 sw=4 sts=4 tw=100: */
